home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue49 / Alfresco / AABinTre.pas next >
Encoding:
Pascal/Delphi Source File  |  1999-07-25  |  25.8 KB  |  860 lines

  1. {*********************************************************}
  2. {* AABinTre                                              *}
  3. {* Copyright (c) Julian M Bucknall 1998-1999             *}
  4. {* All rights reserved.                                  *}
  5. {*********************************************************}
  6. {* Algorithms Alfresco binary tree unit                  *}
  7. {*********************************************************}
  8.  
  9. {Note: this unit is released as freeware. In other words, you are free
  10.        to use this unit in your own applications, however I retain all
  11.        copyright to the code. JMB}
  12.  
  13. unit AABinTre;
  14.  
  15. interface
  16.  
  17. uses
  18.   SysUtils;
  19.  
  20. {$IFOPT D+}
  21. {$DEFINE InDebugMode}
  22. {$ENDIF}
  23.  
  24. {$DEFINE UseNodeManager}
  25.  
  26. const
  27.   PageNodeCount = 30;
  28.  
  29. type
  30.   TaaCompareFunction = function (aItem1, aItem2 : pointer) : integer;
  31.  
  32. const
  33.   aaLeft = true;
  34.   aaRight= false;
  35.  
  36. type
  37.   TaaBinaryTree = class;     {forward declaration}
  38.  
  39.   TaaTraversalMode = (       {different traversal modes..}
  40.          tmPreOrder,         {..pre-order}
  41.          tmInOrder,          {..in-order}
  42.          tmPostOrder,        {..post-order}
  43.          tmLevelOrder);      {..level-order}
  44.  
  45.   PaaBTNode = ^TaaBTNode;    {binary tree node}
  46.   TaaBTNode = packed record
  47.     btParent : PaaBTNode;
  48.     btChild  : array [boolean] of PaaBTNode;
  49.     btData   : pointer;
  50.     btExtra  : longint;
  51.   end;
  52.  
  53.   TaaDisposeItem = procedure (aItem : pointer);
  54.     {-procedure prototype to dispose of an item}
  55.  
  56.   TaaProcessNode = function (aNode      : PaaBTNode;
  57.                              aExtraData : pointer) : boolean;
  58.     {-function prototype to process a node}
  59.  
  60.   TaaBinaryTree = class      {binary tree class}
  61.     private
  62.       FCount   : integer;
  63.       FDispose : TaaDisposeItem;
  64.       FHead    : PaaBTNode;
  65.     protected
  66.       function btLevelOrder(aAction : TaaProcessNode;
  67.                             aExtraData : pointer) : PaaBTNode;
  68.       function btNoRecInOrder(aAction : TaaProcessNode;
  69.                               aExtraData : pointer) : PaaBTNode;
  70.       function btNoRecPostOrder(aAction : TaaProcessNode;
  71.                                 aExtraData : pointer) : PaaBTNode;
  72.       function btNoRecPreOrder(aAction : TaaProcessNode;
  73.                                aExtraData : pointer) : PaaBTNode;
  74.       function btRecInOrder(aNode   : PaaBTNode;
  75.                             aAction : TaaProcessNode;
  76.                             aExtraData : pointer) : PaaBTNode;
  77.       function btRecPostOrder(aNode   : PaaBTNode;
  78.                               aAction : TaaProcessNode;
  79.                               aExtraData : pointer) : PaaBTNode;
  80.       function btRecPreOrder(aNode   : PaaBTNode;
  81.                              aAction : TaaProcessNode;
  82.                              aExtraData : pointer) : PaaBTNode;
  83.     public
  84.       constructor Create(aDisposeItem : TaaDisposeItem);
  85.       destructor Destroy; override;
  86.  
  87.       procedure Clear;
  88.       procedure Delete(aNode : PaaBTNode);
  89.       function InsertAt(aParentNode  : PaaBTNode;
  90.                         aAsLeftChild : boolean;
  91.                         aItem        : pointer) : PaaBTNode;
  92.       function Root : PaaBTNode;
  93.       function Traverse(aMode         : TaaTraversalMode;
  94.                         aAction       : TaaProcessNode;
  95.                         aExtraData    : pointer;
  96.                         aUseRecursion : boolean) : PaaBTNode;
  97.  
  98.       property Count : integer read FCount;
  99.   end;
  100.  
  101.   TaaBinarySearchTree = class      {binary search tree class}
  102.     private
  103.       FBinTree : TaaBinaryTree;
  104.       FCompare : TaaCompareFunction;
  105.       FCount   : integer;
  106.     protected
  107.       function bstFindItem(aItem    : pointer;
  108.                        var aNode    : PaaBTNode;
  109.                        var aUseLeft : boolean) : boolean;
  110.     public
  111.       constructor Create(aCompare : TaaCompareFunction;
  112.                          aDispose : TaaDisposeItem);
  113.       destructor Destroy; override;
  114.  
  115.       procedure Clear;
  116.       procedure Delete(aItem : pointer);
  117.       function Find(aKeyItem : pointer) : pointer;
  118.       procedure Insert(aItem : pointer);
  119.       function Traverse(aMode         : TaaTraversalMode;
  120.                         aAction       : TaaProcessNode;
  121.                         aExtraData    : pointer;
  122.                         aUseRecursion : boolean) : pointer;
  123.  
  124.       property Count : integer read FCount;
  125.       property BinaryTree : TaaBinaryTree read FBinTree;
  126.   end;
  127.  
  128. type
  129.   TaaDrawBinaryNode = procedure (aNode  : PaaBTNode;
  130.                                  aStrip : integer;
  131.                                  aColumn: integer;
  132.                                  aParentStrip : integer;
  133.                                  aParentColumn: integer;
  134.                                  aExtraData   : pointer);
  135.  
  136. procedure DrawBinaryTree(aTree      : TObject;
  137.                          aDrawNode  : TaaDrawBinaryNode;
  138.                          aExtraData : pointer);
  139.  
  140. implementation
  141.  
  142. uses
  143.   AALnkLst;
  144.  
  145. {===NodeManager for binary tree nodes================================}
  146. type
  147.   PnmPage = ^TnmPage;
  148.   TnmPage = packed record
  149.     nmpNext  : PnmPage;
  150.     nmpNodes : array [0..pred(PageNodeCount)] of TaaBTNode;
  151.   end;
  152. {--------}
  153. var
  154.   nmFreeList : PaaBTNode;
  155.   nmPageList : PnmPage;
  156. {--------}
  157. procedure nmFreeNode(aNode : PaaBTNode);
  158. begin
  159.   {$IFDEF UseNodeManager}
  160.   {add the node to the top of the free list}
  161.   aNode^.btParent := nmFreeList;
  162.   nmFreeList := aNode;
  163.   {$ELSE}
  164.   Dispose(aNode);
  165.   {$ENDIF}
  166. end;
  167. {--------}
  168. procedure nmAllocPage;
  169. var
  170.   NewPage : PnmPage;
  171.   i       : integer;
  172. begin
  173.   {get a new page}
  174.   New(NewPage);
  175.   {add it to the current list of pages}
  176.   NewPage^.nmpNext := nmPageList;
  177.   nmPageList := NewPage;
  178.   {add all the nodes on the page to the free list}
  179.   for i := 0 to pred(PageNodeCount) do
  180.     nmFreeNode(@NewPage^.nmpNodes[i]);
  181. end;
  182. {--------}
  183. function nmAllocNode : PaaBTNode;
  184. begin
  185.   {$IFDEF UseNodeManager}
  186.   {if the free list is empty, allocate a new page of nodes}
  187.   if (nmFreeList = nil) then
  188.     nmAllocPage;
  189.   {return the first node on the free list}
  190.   Result := nmFreeList;
  191.   nmFreeList := Result^.btParent;
  192.   {$ELSE}
  193.   New(Result);
  194.   {$ENDIF}
  195.   {$IFDEF InDebugMode}
  196.   Result^.btParent := nil;
  197.   Result^.btChild[aaLeft] := nil;
  198.   Result^.btChild[aaRight] := nil;
  199.   Result^.btData := nil;
  200.   Result^.btExtra := 0;
  201.   {$ENDIF}
  202. end;
  203. {====================================================================}
  204.  
  205.  
  206. {===Helper routines==================================================}
  207. function DisposeNode(aNode      : PaaBTNode;
  208.                      aExtraData : pointer) : boolean; far;
  209. var
  210.   DisposeItem : TaaDisposeItem absolute aExtraData;
  211. begin
  212.   if (aExtraData <> nil) then
  213.     DisposeItem(aNode^.btData);
  214.   nmFreeNode(aNode);
  215.   Result := true;
  216. end;
  217. {====================================================================}
  218.  
  219.  
  220. {===TaaBinaryTree====================================================}
  221. constructor TaaBinaryTree.Create(aDisposeItem : TaaDisposeItem);
  222. begin
  223.   inherited Create;
  224.   FDispose := aDisposeItem;
  225.   {allocate a head node, eventually the root node of the tree will be
  226.    its left child}
  227.   FHead := nmAllocNode;
  228.   FHead^.btParent := nil;
  229.   FHead^.btChild[aaLeft] := nil;
  230.   FHead^.btChild[aaRight] := nil;
  231.   FHead^.btData := nil;
  232.   FHead^.btExtra := 0;
  233. end;
  234. {--------}
  235. destructor TaaBinaryTree.Destroy;
  236. begin
  237.   Clear;
  238.   nmFreeNode(FHead);
  239.   inherited Destroy;
  240. end;
  241. {--------}
  242. function TaaBinaryTree.btLevelOrder(aAction : TaaProcessNode;
  243.                                     aExtraData : pointer) : PaaBTNode;
  244. var
  245.   Queue : TaaQueue;
  246.   Node  : PaaBTNode;
  247. begin
  248.   {assume we won't get a node selected}
  249.   Result := nil;
  250.   {simple case first}
  251.   if (FCount = 0) then
  252.     Exit;
  253.   {create the queue}
  254.   Queue := TaaQueue.Create;
  255.   try
  256.     {enqueue the root}
  257.     Queue.Enqueue(FHead^.btChild[aaLeft]);
  258.     {continue until the queue is empty}
  259.     while not Queue.IsEmpty do begin
  260.       {get the node at the head of the queue}
  261.       Node := Queue.Dequeue;
  262.       {perform the action on it, if this returns false (ie, don't
  263.        continue), return this node}
  264.       if not aAction(Node, aExtraData) then begin
  265.         Result := Node;
  266.         Queue.Clear;
  267.       end
  268.       {otherwise, continue}
  269.       else begin
  270.         {enqueue the left child, if it's not nil}
  271.         if (Node^.btChild[aaLeft] <> nil) then
  272.           Queue.Enqueue(Node^.btChild[aaLeft]);
  273.         {enqueue the right child, if it's not nil}
  274.         if (Node^.btChild[aaRight] <> nil) then
  275.           Queue.Enqueue(Node^.btChild[aaRight]);
  276.       end;
  277.     end;
  278.   finally
  279.     {destroy the queue}
  280.     Queue.Free;
  281.   end;
  282. end;
  283. {--------}
  284. function TaaBinaryTree.btNoRecInOrder(aAction : TaaProcessNode;
  285.                                       aExtraData : pointer) : PaaBTNode;
  286. var
  287.   Stack : TaaStack;
  288.   Node  : PaaBTNode;
  289. begin
  290.   {assume we won't get a node selected}
  291.   Result := nil;
  292.   {simple case first}
  293.   if (FCount = 0) then
  294.     Exit;
  295.   {create the stack}
  296.   Stack := TaaStack.Create;
  297.   try
  298.     {push the root}
  299.     Stack.Push(FHead^.btChild[aaLeft]);
  300.     {continue until the stack is empty}
  301.     while not Stack.IsEmpty do begin
  302.       {get the node at the head of the queue}
  303.       Node := Stack.Pop;
  304.       {if it's nil, pop the next node, perform the action on it, if
  305.        this returns false (ie, don't continue), return this node}
  306.       if (Node = nil) then begin
  307.         Node := Stack.Pop;
  308.         if not aAction(Node, aExtraData) then begin
  309.           Result := Node;
  310.           Stack.Clear;
  311.         end;
  312.       end
  313.       {otherwise, the children of the node have not been pushed yet}
  314.       else begin
  315.         {push the right child, if it's not nil}
  316.         if (Node^.btChild[aaRight] <> nil) then
  317.           Stack.Push(Node^.btChild[aaRight]);
  318.         {push the node, followed by a nil pointer}
  319.         Stack.Push(Node);
  320.         Stack.Push(nil);
  321.         {push the left child, if it's not nil}
  322.         if (Node^.btChild[aaLeft] <> nil) then
  323.           Stack.Push(Node^.btChild[aaLeft]);
  324.       end;
  325.     end;
  326.   finally
  327.     {destroy the stack}
  328.     Stack.Free;
  329.   end;
  330. end;
  331. {--------}
  332. function TaaBinaryTree.btNoRecPostOrder(aAction : TaaProcessNode;
  333.                                         aExtraData : pointer) : PaaBTNode;
  334. var
  335.   Stack : TaaStack;
  336.   Node  : PaaBTNode;
  337. begin
  338.   {assume we won't get a node selected}
  339.   Result := nil;
  340.   {simple case first}
  341.   if (FCount = 0) then
  342.     Exit;
  343.   {create the stack}
  344.   Stack := TaaStack.Create;
  345.   try
  346.     {push the root}
  347.     Stack.Push(FHead^.btChild[aaLeft]);
  348.     {continue until the stack is empty}
  349.     while not Stack.IsEmpty do begin
  350.       {get the node at the head of the queue}
  351.       Node := Stack.Pop;
  352.       {if it's nil, pop the next node, perform the action on it, if
  353.        this returns false (ie, don't continue), return this node}
  354.       if (Node = nil) then begin
  355.         Node := Stack.Pop;
  356.         if not aAction(Node, aExtraData) then begin
  357.           Result := Node;
  358.           Stack.Clear;
  359.         end;
  360.       end
  361.       {otherwise, the children of the node have not been pushed yet}
  362.       else begin
  363.         {push the node, followed by a nil pointer}
  364.         Stack.Push(Node);
  365.         Stack.Push(nil);
  366.         {push the right child, if it's not nil}
  367.         if (Node^.btChild[aaRight] <> nil) then
  368.           Stack.Push(Node^.btChild[aaRight]);
  369.         {push the left child, if it's not nil}
  370.         if (Node^.btChild[aaLeft] <> nil) then
  371.           Stack.Push(Node^.btChild[aaLeft]);
  372.       end;
  373.     end;
  374.   finally
  375.     {destroy the stack}
  376.     Stack.Free;
  377.   end;
  378. end;
  379. {--------}
  380. function TaaBinaryTree.btNoRecPreOrder(aAction : TaaProcessNode;
  381.                                        aExtraData : pointer) : PaaBTNode;
  382. var
  383.   Stack : TaaStack;
  384.   Node  : PaaBTNode;
  385. begin
  386.   {assume we won't get a node selected}
  387.   Result := nil;
  388.   {simple case first}
  389.   if (FCount = 0) then
  390.     Exit;
  391.   {create the stack}
  392.   Stack := TaaStack.Create;
  393.   try
  394.     {push the root}
  395.     Stack.Push(FHead^.btChild[aaLeft]);
  396.     {continue until the stack is empty}
  397.     while not Stack.IsEmpty do begin
  398.       {get the node at the head of the queue}
  399.       Node := Stack.Pop;
  400.       {perform the action on it, if this returns false (ie, don't
  401.        continue), return this node}
  402.       if not aAction(Node, aExtraData) then begin
  403.         Result := Node;
  404.         Stack.Clear;
  405.       end
  406.       {otherwise, continue}
  407.       else begin
  408.         {push the right child, if it's not nil}
  409.         if (Node^.btChild[aaRight] <> nil) then
  410.           Stack.Push(Node^.btChild[aaRight]);
  411.         {push the left child, if it's not nil}
  412.         if (Node^.btChild[aaLeft] <> nil) then
  413.           Stack.Push(Node^.btChild[aaLeft]);
  414.       end;
  415.     end;
  416.   finally
  417.     {destroy the stack}
  418.     Stack.Free;
  419.   end;
  420. end;
  421. {--------}
  422. function TaaBinaryTree.btRecInOrder(aNode   : PaaBTNode;
  423.                                     aAction : TaaProcessNode;
  424.                                     aExtraData : pointer) : PaaBTNode;
  425. begin
  426.   Result := nil;
  427.   if (aNode^.btChild[aaLeft] <> nil) then begin
  428.     Result := btRecInOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  429.     if (Result <> nil) then Exit;
  430.   end;
  431.   if not aAction(aNode, aExtraData) then begin
  432.     Result := aNode;
  433.     Exit;
  434.   end;
  435.   if (aNode^.btChild[aaRight] <> nil) then begin
  436.     Result := btRecInOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  437.   end;
  438. end;
  439. {--------}
  440. function TaaBinaryTree.btRecPostOrder(aNode   : PaaBTNode;
  441.                                       aAction : TaaProcessNode;
  442.                                       aExtraData : pointer) : PaaBTNode;
  443. begin
  444.   Result := nil;
  445.   if (aNode^.btChild[aaLeft] <> nil) then begin
  446.     Result := btRecPostOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  447.     if (Result <> nil) then Exit;
  448.   end;
  449.   if (aNode^.btChild[aaRight] <> nil) then begin
  450.     Result := btRecPostOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  451.     if (Result <> nil) then Exit;
  452.   end;
  453.   if not aAction(aNode, aExtraData) then begin
  454.     Result := aNode;
  455.   end;
  456. end;
  457. {--------}
  458. function TaaBinaryTree.btRecPreOrder(aNode   : PaaBTNode;
  459.                                      aAction : TaaProcessNode;
  460.                                      aExtraData : pointer) : PaaBTNode;
  461. begin
  462.   Result := nil;
  463.   if not aAction(aNode, aExtraData) then begin
  464.     Result := aNode;
  465.     Exit;
  466.   end;
  467.   if (aNode^.btChild[aaLeft] <> nil) then begin
  468.     Result := btRecPreOrder(aNode^.btChild[aaLeft], aAction, aExtraData);
  469.     if (Result <> nil) then Exit;
  470.   end;
  471.   if (aNode^.btChild[aaRight] <> nil) then begin
  472.     Result := btRecPreOrder(aNode^.btChild[aaRight], aAction, aExtraData);
  473.   end;
  474. end;
  475. {--------}
  476. procedure TaaBinaryTree.Clear;
  477. begin
  478.   {to clear a binary tree, we perform a postorder traversal, with the
  479.    action on each node being its disposal}
  480.   btNoRecPostOrder(DisposeNode, @FDispose);
  481.   FCount := 0;
  482.   FHead^.btChild[aaLeft] := nil;
  483. end;
  484. {--------}
  485. procedure TaaBinaryTree.Delete(aNode : PaaBTNode);
  486. var
  487.   HaveLeftChild : boolean;
  488.   AmLeftChild   : boolean;
  489. begin
  490.   if (aNode = nil)then
  491.     raise Exception.Create('TaaBinaryTree.Delete: node is nil');
  492.   {find out whether we have a single child and which one it is; if we
  493.    find that there are two children raise an exception}
  494.   if (aNode.btChild[aaLeft] <> nil) then begin
  495.     if (aNode.btChild[aaRight] <> nil) then
  496.       raise Exception.Create(
  497.           'TaaBinaryTree.Delete: cannot delete this node');
  498.     HaveLeftChild := true;
  499.   end
  500.   else
  501.     HaveLeftChild := false;
  502.   {find out whether we're a left or right child of our parent}
  503.   AmLeftChild := aNode^.btParent^.btChild[aaLeft] = aNode;
  504.   {set the child link of our parent to our child link}
  505.   aNode^.btParent^.btChild[AmLeftChild] :=
  506.      aNode^.btChild[HaveLeftChild];
  507.   {free the node}
  508.   if Assigned(FDispose) then
  509.     FDispose(aNode^.btData);
  510.   nmFreeNode(aNode);
  511.   dec(FCount);
  512. end;
  513. {--------}
  514. function TaaBinaryTree.InsertAt(aParentNode  : PaaBTNode;
  515.                                 aAsLeftChild : boolean;
  516.                                 aItem        : pointer) : PaaBTNode;
  517. begin
  518.   {if the parent node is nil, assume this is inserting the root}
  519.   if (aParentNode = nil) then begin
  520.     aParentNode := FHead;
  521.     aAsLeftChild := true;
  522.   end;
  523.   {check to see the child link isn't already set}
  524.   if (aParentNode^.btChild[aAsLeftChild] <> nil) then
  525.     raise Exception.Create('TaaBinaryTree.InsertAt: cannot insert here');
  526.   {allocate a new node and insert as the required child of the parent}
  527.   Result := nmAllocNode;
  528.   Result^.btParent := aParentNode;
  529.   Result^.btChild[aaLeft] := nil;
  530.   Result^.btChild[aaRight] := nil;
  531.   Result^.btData := aItem;
  532.   Result^.btExtra := 0;
  533.   aParentNode^.btChild[aAsLeftChild] := Result;
  534.   inc(FCount);
  535. end;
  536. {--------}
  537. function TaaBinaryTree.Root : PaaBTNode;
  538. begin
  539.   Result := FHead^.btChild[aaLeft];
  540. end;
  541. {--------}
  542. function TaaBinaryTree.Traverse(aMode         : TaaTraversalMode;
  543.                                 aAction       : TaaProcessNode;
  544.                                 aExtraData    : pointer;
  545.                                 aUseRecursion : boolean) : PaaBTNode;
  546. begin
  547.   case aMode of
  548.     tmPreOrder :
  549.       if aUseRecursion then
  550.         Result := btRecPreOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  551.       else
  552.         Result := btNoRecPreOrder(aAction, aExtraData);
  553.     tmInOrder :
  554.       if aUseRecursion then
  555.         Result := btRecInOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  556.       else
  557.         Result := btNoRecInOrder(aAction, aExtraData);
  558.     tmPostOrder :
  559.       if aUseRecursion then
  560.         Result := btRecPostOrder(FHead^.btChild[aaLeft], aAction, aExtraData)
  561.       else
  562.         Result := btNoRecPostOrder(aAction, aExtraData);
  563.     tmLevelOrder :
  564.       Result := btLevelOrder(aAction, aExtraData);
  565.   else
  566.     Result := nil;
  567.   end;
  568. end;
  569. {====================================================================}
  570.  
  571.  
  572. {===TaaBinarySearchTree==============================================}
  573. constructor TaaBinarySearchTree.Create(aCompare : TaaCompareFunction;
  574.                                        aDispose : TaaDisposeItem);
  575. begin
  576.   inherited Create;
  577.   FCompare := aCompare;
  578.   FBinTree := TaaBinaryTree.Create(aDispose);
  579. end;
  580. {--------}
  581. destructor TaaBinarySearchTree.Destroy;
  582. begin
  583.   FBinTree.Free;
  584.   inherited Destroy;
  585. end;
  586. {--------}
  587. function TaaBinarySearchTree.bstFindItem(aItem    : pointer;
  588.                                      var aNode    : PaaBTNode;
  589.                                      var aUseLeft : boolean) : boolean;
  590. var
  591.   Walker : PaaBTNode;
  592.   CmpResult : integer;
  593. begin
  594.   Result := false;
  595.   if (FCount = 0) then begin
  596.     aNode := nil;
  597.     aUseLeft := true;
  598.     Exit;
  599.   end;
  600.   Walker := FBinTree.Root;
  601.   CmpResult := FCompare(aItem, Walker^.btData);
  602.   while (CmpResult <> 0) do begin
  603.     if (CmpResult < 0) then begin
  604.       if (Walker^.btChild[aaLeft] = nil) then begin
  605.         aNode := Walker;
  606.         aUseLeft := true;
  607.         Exit;
  608.       end;
  609.       Walker := Walker^.btChild[aaLeft];
  610.     end
  611.     else begin
  612.       if (Walker^.btChild[aaRight] = nil) then begin
  613.         aNode := Walker;
  614.         aUseLeft := false;
  615.         Exit;
  616.       end;
  617.       Walker := Walker^.btChild[aaRight];
  618.     end;
  619.     CmpResult := FCompare(aItem, Walker^.btData);
  620.   end;
  621.   Result := true;
  622.   aNode := Walker;
  623. end;
  624. {--------}
  625. procedure TaaBinarySearchTree.Clear;
  626. begin
  627.   FBinTree.Clear;
  628.   FCount := 0;
  629. end;
  630. {--------}
  631. procedure TaaBinarySearchTree.Delete(aItem : pointer);
  632. var
  633.   Walker  : PaaBTNode;
  634.   Node    : PaaBTNode;
  635.   UseLeft : boolean;
  636.   Temp    : pointer;
  637. begin
  638.   {attempt to find the item; signal error if not found}
  639.   if not bstFindItem(aItem, Node, UseLeft) then
  640.     raise Exception.Create('TaaBinarySearchTree.Delete: item not found');
  641.   {if the node has two children, find the largest node that is smaller
  642.    than the one we want to delete, and swap over the items}
  643.   if (Node^.btChild[aaLeft] <> nil) and
  644.      (Node^.btChild[aaRight] <> nil) then begin
  645.     Walker := Node^.btChild[aaLeft];
  646.     while (Walker^.btChild[aaRight] <> nil) do
  647.       Walker := Node^.btChild[aaRight];
  648.     Temp := Walker^.btData;
  649.     Walker^.btData := Node^.btData;
  650.     Node^.btData := Temp;
  651.     Node := Walker;
  652.   end;
  653.   {delete the node}
  654.   FBinTree.Delete(Node);
  655.   dec(FCount);
  656. end;
  657. {--------}
  658. function TaaBinarySearchTree.Find(aKeyItem : pointer) : pointer;
  659. var
  660.   Node : PaaBTNode;
  661.   UseLeft : boolean;
  662. begin
  663.   if bstFindItem(aKeyItem, Node, UseLeft) then
  664.     Result := Node^.btData
  665.   else
  666.     Result := nil;
  667. end;
  668. {--------}
  669. procedure TaaBinarySearchTree.Insert(aItem : pointer);
  670. var
  671.   Node : PaaBTNode;
  672.   UseLeft : boolean;
  673. begin
  674.   {first attempt to find the item; if found, it's an error}
  675.   if bstFindItem(aItem, Node, UseLeft) then
  676.     raise Exception.Create(
  677.        'TaaBinarySearchTree.Insert: duplicate keys not allowed');
  678.   {this returns a node, so insert there}
  679.   FBinTree.InsertAt(Node, UseLeft, aItem);
  680.   inc(FCount);
  681. end;
  682. {--------}
  683. function TaaBinarySearchTree.Traverse(aMode         : TaaTraversalMode;
  684.                                       aAction       : TaaProcessNode;
  685.                                       aExtraData    : pointer;
  686.                                       aUseRecursion : boolean) : pointer;
  687. var
  688.   Node : PaaBTNode;
  689. begin
  690.   Node := FBinTree.Traverse(aMode, aAction, aExtraData, aUseRecursion);
  691.   if (Node = nil) then
  692.     Result := nil
  693.   else
  694.     Result := Node^.btData;
  695. end;
  696. {====================================================================}
  697.  
  698.  
  699. {===Drawing a binary tree============================================}
  700. type
  701.   PNodePosn = ^TNodePosn;
  702.   TNodePosn = packed record
  703.     npStrip  : integer;
  704.     npColumn : integer;
  705.   end;
  706. {--------}
  707. procedure DrawBinaryTree(aTree      : TObject;
  708.                          aDrawNode  : TaaDrawBinaryNode;
  709.                          aExtraData : pointer);
  710.   {------}
  711.   function GenPosNode(aNode   : PaaBTNode;
  712.                       aStrip  : integer;
  713.                   var aColumn : integer) : PaaBTNode;
  714.   var
  715.     OurPosNode : PaaBTNode;
  716.     OurPosition : PNodePosn;
  717.   begin
  718.     {allocate ourselves a node and a position}
  719.     OurPosNode := nmAllocNode;
  720.     FillChar(OurPosNode^, sizeof(OurPosNode^), 0);
  721.     New(OurPosition);
  722.     OurPosNode^.btData := OurPosition;
  723.  
  724.     {visit the left subtree}
  725.     if (aNode^.btChild[aaLeft] <> nil) then begin
  726.       OurPosNode^.btChild[aaLeft] :=
  727.          GenPosNode(aNode^.btChild[aaLeft], succ(aStrip), aColumn);
  728.       OurPosNode^.btChild[aaLeft]^.btParent := OurPosNode;
  729.     end;
  730.  
  731.     {store our position, increment the column since we're there now}
  732.     OurPosition^.npStrip := aStrip;
  733.     OurPosition^.npColumn := aColumn;
  734.     inc(aColumn);
  735.  
  736.     {visit the right subtree}
  737.     if (aNode^.btChild[aaRight] <> nil) then begin
  738.       OurPosNode^.btChild[aaRight] :=
  739.         GenPosNode(aNode^.btChild[aaRight], succ(aStrip), aColumn);
  740.       OurPosNode^.btChild[aaRight]^.btParent := OurPosNode;
  741.     end;
  742.  
  743.     Result := OurPosNode;
  744.   end;
  745.   {------}
  746.   procedure DestroyPosNode(aNode : PaaBTNode);
  747.   begin
  748.     {destroy the left subtree}
  749.     if (aNode^.btChild[aaLeft] <> nil) then
  750.       DestroyPosNode(aNode^.btChild[aaLeft]);
  751.     {destroy the right subtree}
  752.     if (aNode^.btChild[aaRight] <> nil) then
  753.       DestroyPosNode(aNode^.btChild[aaRight]);
  754.     {destroy this node}
  755.     Dispose(PNodePosn(aNode^.btData));
  756.     nmFreeNode(aNode);
  757.   end;
  758.   {------}
  759. var
  760.   BinTree : TaaBinaryTree;
  761.   Strip, Column : integer;
  762.   PStrip, PColumn : integer;
  763.   PosRoot : PaaBTNode;
  764.   Queue   : TaaQueue;
  765.   Node    : PaaBTNode;
  766.   PosNode : PaaBTNode;
  767. begin
  768.   {get a hold of the actual binary tree}
  769.   if (aTree is TaaBinaryTree) then
  770.     BinTree := TaaBinaryTree(aTree)
  771.   else if (aTree is TaaBinarySearchTree) then
  772.     BinTree := TaaBinarySearchTree(aTree).BinaryTree
  773.   else
  774.     Exit;
  775.  
  776.   {simple case first}
  777.   if (BinTree.Count = 0) then
  778.     Exit;
  779.  
  780.   {--first pass--}
  781.   Strip := 0;
  782.   Column := 0;
  783.   PosRoot := GenPosNode(BinTree.Root, Strip, Column);
  784.  
  785.   {--second pass--}
  786.   try
  787.     {create the queue}
  788.     Queue := TaaQueue.Create;
  789.     try
  790.       {enqueue the roots}
  791.       Queue.Enqueue(BinTree.Root);
  792.       Queue.Enqueue(PosRoot);
  793.       {continue until the queue is empty}
  794.       while not Queue.IsEmpty do begin
  795.         {get the nodes at the head of the queue}
  796.         Node := Queue.Dequeue;
  797.         PosNode := Queue.Dequeue;
  798.         {draw the node}
  799.         if (PosNode = PosRoot) then begin
  800.           PStrip := -1;
  801.           PColumn := -1;
  802.         end
  803.         else with PNodePosn(PosNode^.btParent^.btData)^ do begin
  804.           PStrip := npStrip;
  805.           PColumn := npColumn;
  806.         end;
  807.         with PNodePosn(PosNode^.btData)^ do
  808.           aDrawNode(Node, npStrip, npColumn,
  809.                           PStrip, PColumn, aExtraData);
  810.         {enqueue the left children, if the first is not nil}
  811.         if (Node^.btChild[aaLeft] <> nil) then begin
  812.           Queue.Enqueue(Node^.btChild[aaLeft]);
  813.           Queue.Enqueue(PosNode^.btChild[aaLeft]);
  814.         end;
  815.         {enqueue the right children, if the first is not nil}
  816.         if (Node^.btChild[aaRight] <> nil) then begin
  817.           Queue.Enqueue(Node^.btChild[aaRight]);
  818.           Queue.Enqueue(PosNode^.btChild[aaRight]);
  819.         end;
  820.       end;
  821.     finally
  822.       {destroy the queue}
  823.       Queue.Free;
  824.     end;
  825.   finally
  826.     {now destroy the position binary tree}
  827.     DestroyPosNode(PosRoot);
  828.   end;
  829. end;
  830. {====================================================================}
  831.  
  832.  
  833. procedure FinalizeUnit; far;
  834. var
  835.   Temp : PnmPage;
  836. begin
  837.   {destroy all the single node pages}
  838.   Temp := nmPageList;
  839.   while (Temp <> nil) do begin
  840.     nmPageList := Temp^.nmpNext;
  841.     Dispose(Temp);
  842.     Temp := nmPageList;
  843.   end;
  844. end;
  845.  
  846. initialization
  847.   nmFreeList := nil;
  848.   nmPageList := nil;
  849.   {$IFDEF Windows}
  850.   AddExitProc(FinalizeUnit);
  851.   {$ENDIF}
  852.  
  853. {$IFDEF Win32}
  854. finalization
  855.   FinalizeUnit;
  856. {$ENDIF}
  857.  
  858. end.
  859.  
  860.